// region 验证实现

/**
 * 验证身份证号码
 * @return {boolean}
 */
function validateIdcardNumber(rule, value, callback, source) {
  return _validateIdcardNumber(value)
}

/**
 * 验证车牌号码
 * @return {boolean}
 */
function validatePlateNumber(rule, value, callback, source) {
  return /(^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$)/.test(value)
}

/**
 * 验证手机号码
 * @return {boolean}
 */
function validatePhoneNumber(rule, value, callback, source) {
  return /^1[3456789][0-9]{9}$/.test(value)
}

/**
 * 验证IP地址
 * @return {boolean}
 */
function validateIP(strIP) {
  if (/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/g.test(strIP)) {
    if (RegExp.$1 < 256 && RegExp.$2 < 256 && RegExp.$3 < 256 && RegExp.$4 < 256) {
      return true
    }
  }
  return false
}

/**
 * 验证字符串是否只由汉字、数字、字母组成
 * @return {boolean}
 */
function validateChineseOrNumberOrLetter(str) {
  return /^[0-9a-zA-Z\u4e00-\u9fa5]+$/.test(str)
}

/**
 * 验证Email
 * @return {boolean}
 */
function validateEmail(rule, value, callback, source) {
  return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(value)
}

// endregion

// region 私有函数
/**
 * 判断值是否为空
 * @param value 值
 * @return {boolean}
 * @private
 */
function _blank(value) {
  return value === undefined || value === null || value === ''
}

/**
 * 判断规则是否可选填
 * @param rule
 * @return {boolean}
 * @private
 */
function _optional(rule) {
  return rule.required === undefined || rule.required === null || (rule.required === false)
}

/**
 * 封装验证器
 * @param rule 表示当前的验证规则
 * @param value 表示当前验证的值
 * @param callback 为回调函数,若验证不通过调用callback(false),若验证通过 调用callback()。
 * @param source 为整个表单的数据
 * @param implement 具体验证实现类
 * @private
 */
function _validator(rule, value, callback, source, implement) {
  if (_blank(value) && _optional(rule)) {
    callback()
    return
  }
  if (_blank(value)) {
    callback(false)
    return
  }

  if (implement(rule, value, callback, source) === true) {
    callback()
  } else {
    callback(false)
  }
}


/**
 * 验证身份号码
 * @param num
 * @return {boolean}
 * @private
 */
function _validateIdcardNumber(num) {
  const factorArr = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1]
  const parityBit = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
  const varArray = []
  let lngProduct = 0
  let intCheckDigit
  const intStrLen = num.length
  const idNumber = num
  // initialize
  if ((intStrLen !== 15) && (intStrLen !== 18)) {
    return false
  }
  // check and set value
  for (var i = 0; i < intStrLen; i++) {
    varArray[i] = idNumber.charAt(i)
    if ((varArray[i] < '0' || varArray[i] > '9') && (i !== 17)) {
      return false
    } else if (i < 17) {
      varArray[i] = varArray[i] * factorArr[i]
    }
  }
  if (intStrLen === 18) {
    //check date
    const date8 = idNumber.substring(6, 14)
    if (_isDate8(date8) === false) {
      return false
    }
    // calculate the sum of the products
    for (i = 0; i < 17; i++) {
      lngProduct = lngProduct + varArray[i]
    }
    // calculate the check digit
    intCheckDigit = parityBit[lngProduct % 11]
    // check last digit
    if (varArray[17] !== intCheckDigit) {
      return false
    }
  } else { //length is 15
    //check date
    const date6 = idNumber.substring(6, 12)
    if (_isDate6(date6) === false) {

      return false
    }
  }
  return true
}

function _isDate6(sDate) {
  if (!/^[0-9]{6}$/.test(sDate)) {
    return false
  }
  const year = sDate.substring(0, 4)
  const month = sDate.substring(4, 6)
  if (year < 1700 || year > 2500) return false
  if (month < 1 || month > 12) return false
  return true
}

function _isDate8(sDate) {
  if (!/^[0-9]{8}$/.test(sDate)) {
    return false
  }
  const year = sDate.substring(0, 4)
  const month = sDate.substring(4, 6)
  const day = sDate.substring(6, 8)
  const iaMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  if (year < 1700 || year > 2500) return false
  if (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) iaMonthDays[1] = 29
  if (month < 1 || month > 12) return false
  if (day < 1 || day > iaMonthDays[month - 1]) return false
  return true
}

// endregion


module.exports = {
  plateNumber: (r, v, c, s) => _validator(r, v, c, s, validatePlateNumber),
  phoneNumber: (r, v, c, s) => _validator(r, v, c, s, validatePhoneNumber),
  idcardNumber: (r, v, c, s) => _validator(r, v, c, s, validateIdcardNumber),
  email: (r, v, c, s) => _validator(r, v, c, s, validateEmail),
  ip: (r, v, c, s) => _validator(r, v, c, s, validateIP),
  chineseOrNumberOrLetter: (r, v, c, s) => _validator(r, v, c, s, validateChineseOrNumberOrLetter),
}